using System;
using System.Collections.Generic;
using System.IO;
using System.Text;

namespace CVS
{
    public interface IGestorRepositorios
    {
        List<IRepositorio> Repositorios { get; set; }

        IRepositorio ObtemRepositorio(string rep_number);

        void CarregaRepositorios(string filename);

        void GravaRepositorios(string filename);
    }

    public interface IRepositorio
    {
        List<IFicheiro> Ficheiros { get; set; }

        IFicheiro ObtemFicheiro(string filename);

        string Id { get; set; }

        string EnderecoReplicaPrincipal { get; set; }

        string Nome { get; set; }

        bool Alterado { get; set; }

        List<string> Replicas { get; set; }

        int Versao { get; set; }
    }

    public interface IFicheiro
    {
        string Conteudo { get; set; }

        string Nome { get; set; }

        bool Alterado { get; set; }
    }
    [Serializable]
    public class GestorRepositorios : IGestorRepositorios
    {
        private enum TipoLinha
        {
            NOME_REPOSITORIO,
            NOME_FICHEIRO,
            CONTEUDO_FICHEIRO
        }

        private List<IRepositorio> repositorios = new List<IRepositorio>();

        public List<IRepositorio> Repositorios
        {
            get { return repositorios; }
            set { repositorios = value; }
        }

        public IRepositorio ObtemRepositorio(string rep_number)
        {
            foreach (IRepositorio rep in repositorios)
            {
                if (rep.Id.CompareTo(rep_number) == 0)
                {
                    return rep;
                }
            }
            return null;
        }

        /**
         * Formato das linhas :=
         * "#" <Nome_do_repositorio>
         * "$" <Nome_do_ficheiro>
         * <Conteudo>
         **/

        public void CarregaRepositorios(string filename)
        {
            StreamReader sr = null;

            try
            {
                sr = new StreamReader(filename);
                IRepositorio repositorio = null;
                IFicheiro ficheiro = null;
                StringBuilder conteudo = new StringBuilder();

                while (!sr.EndOfStream)
                {
                    string linha = sr.ReadLine();
                    TipoLinha tipoLinha = TipoLinha.CONTEUDO_FICHEIRO;
                    if (linha.Length > 0)
                    {
                        switch (linha[0])
                        {
                            case '#':
                                tipoLinha = TipoLinha.NOME_REPOSITORIO;
                                linha = linha.Remove(0, 1);
                                break;
                            case '$':
                                tipoLinha = TipoLinha.NOME_FICHEIRO;
                                linha = linha.Remove(0, 1);
                                break;
                        }
                    }
                    switch (tipoLinha)
                    {
                        case TipoLinha.NOME_REPOSITORIO:
                            repositorio = CriaRepositorio();
                            repositorio.Nome = linha;
                            repositorios.Add(repositorio);
                            if (ficheiro != null)
                            {
                                ficheiro.Conteudo = conteudo.ToString();
                                conteudo.Length = 0; // Limpar o StringBuilder
                                ficheiro = null;
                            }
                            break;

                        case TipoLinha.NOME_FICHEIRO:
                            if (ficheiro != null)
                            {
                                ficheiro.Conteudo = conteudo.ToString();
                                conteudo.Length = 0;
                            }
                            ficheiro = CriaFicheiro();
                            ficheiro.Nome = linha;
                            if (repositorio != null) // Deve ser sempre diferente de null, mas just in case...
                            {
                                repositorio.Ficheiros.Add(ficheiro);
                            }
                            break;

                        case TipoLinha.CONTEUDO_FICHEIRO:
                            if (ficheiro != null)
                            {
                                conteudo.AppendLine(linha);
                            }
                            break;
                    }
                }
                if (ficheiro != null)
                {
                    ficheiro.Conteudo = conteudo.ToString();
                }
            }
            catch
            {
                repositorios.Clear();
                throw;
            }
            finally
            {
                if (sr != null)
                {
                    sr.Close();
                }
            }
        }

        public void GravaRepositorios(string filename)
        {
            StreamWriter sw = new StreamWriter(filename);
            foreach (IRepositorio r in Repositorios)
            {
                sw.WriteLine("#" + r.Nome);
                foreach (IFicheiro f in r.Ficheiros)
                {
                    sw.WriteLine("$" + f.Nome);
                    sw.Write(f.Conteudo);
                }
            }
            sw.Flush();
            sw.Close();
        }

        public IRepositorio CriaRepositorio()
        {
            return new RepositorioBase();
        }

        public IFicheiro CriaFicheiro()
        {
            return new FicheiroBase();
        }
    }

    [Serializable]
    public class RepositorioBase : IRepositorio
    {
        private int versao=0;
        private string nome;
        private string id;
        private bool alterado;
        private List<IFicheiro> ficheiros = new List<IFicheiro>();
        private List<string> replicas = new List<string>();
        private string enderecoReplicaPrincipal;

        public string EnderecoReplicaPrincipal
        {
            get { return enderecoReplicaPrincipal; }
            set { enderecoReplicaPrincipal = value; }
        }

        public int Versao
        {
            get { return versao; }
            set { versao = value; }
        }

        public bool Alterado
        {
            get { return alterado; }
            set { alterado = value; }
        }

        public string Nome
        {
            get { return nome; }
            set { nome = value; }
        }

        public string Id
        {
            get { return id; }
            set { id = value; }
        }

        public List<IFicheiro> Ficheiros
        {
            get { return ficheiros; }
            set { ficheiros = value; }
        }

        public List<string> Replicas
        {
            get { return replicas; }
            set { replicas = value; }
        }

        public IFicheiro ObtemFicheiro(string filename)
        {
            foreach (IFicheiro file in ficheiros)
            {
                if (file.Nome.CompareTo(filename) == 0)
                {
                    return file;
                }
            }
            return null;
        }
    }

    [Serializable]
    public class FicheiroBase : IFicheiro
    {
        private string nome;
        private string conteudo;
        private bool alterado;

        public string Nome
        {
            get { return nome; }
            set { nome = value; }
        }

        public string Conteudo
        {
            get
            {
                if (conteudo != null)
                {
                    return conteudo;
                }
                return string.Empty;
            }
            set { conteudo = value; }
        }

        public bool Alterado
        {
            get { return alterado; }
            set { alterado = value; }
        }
    }
}
